﻿using JinYuan.DataConvertLib;
using log4net.Core;
using PLCCommunication.PLCType.Omron;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsService1
{
  

    /// <summary>
    /// 定义每个数据读取请求的参数。
    /// </summary>
    public class PLCDataReadRequest
    {
        /// <summary>
        /// PLC起始地址
        /// </summary>
        public string StartAddress { get; set; }
        /// <summary>
        /// 读取长度
        /// </summary>
        public ushort Length { get; set; }
        /// <summary>
        /// 读取区域名称
        /// </summary>
        public string StorageName { get; set; }
        /// <summary>
        /// 读取数据类型
        /// </summary>
        public PLCDataType DataType { get; set; }
    }

    /// <summary>
    /// 存储每次读取操作的结果。
    /// </summary>
    public class PLCDataResult
    {
        /// <summary>
        /// 读取区域名称
        /// </summary>
        public string StorageName { get; set; }
        /// <summary>
        /// 读取数据类型
        /// </summary>
        public PLCDataType DataType { get; set; }
        /// <summary>
        /// 数据
        /// </summary>
        public byte[] Data { get; set; }
        /// <summary>
        /// 是否读取成功
        /// </summary>
        public bool IsSuccess { get; set; }
        /// <summary>
        /// 读取失败的错误信息
        /// </summary>
        public string ErrorMessage { get; set; }
    }

    public class PLCDataReader
    {
        private readonly OmronFinsNet _plc;
        private readonly MqttTopicLogger _mqttTopicLogger = MqttTopicLogger.Instance;
       

        public PLCDataReader(OmronFinsNet plc)
        {
            _plc = plc ?? throw new ArgumentNullException(nameof(plc));
        }

        public async Task<PLCDataResult> ReadDataAsync(PLCDataReadRequest request)
        {
            try
            {
                var data = await _plc.ReadAsync(request.StartAddress, request.Length);
                if (data.IsSuccess && data.Content.Length > 0)
                {
                    _mqttTopicLogger.WritePLCOperation("读取", request.StartAddress, $"长度: {request.Length}, 类型: {request.DataType}", "成功");
                    return new PLCDataResult
                    {
                        StorageName = request.StorageName,
                        DataType = request.DataType,
                        Data = data.Content,
                        IsSuccess = true
                    };
                }
                else
                {
                    _mqttTopicLogger.WritePLCOperation("读取", request.StartAddress, $"长度: {request.Length}, 类型: {request.DataType}", "失败");
                    return new PLCDataResult
                    {
                        StorageName = request.StorageName,
                        DataType = request.DataType,
                        IsSuccess = false,
                        ErrorMessage = "读取PLC数据失败"
                    };
                }
            }
            catch (Exception ex)
            {
                _mqttTopicLogger.WriteSystemError($"读取PLC数据时发生错误：{ex.Message}", ex);
                return new PLCDataResult
                {
                    StorageName = request.StorageName,
                    DataType = request.DataType,
                    IsSuccess = false,
                    ErrorMessage = ex.Message
                };
            }
        }

        /// <summary>
        /// 写入 Float 数据到 PLC
        /// </summary>
        /// <param name="address">PLC 地址</param>
        /// <param name="value">要写入的 Float 值</param>
        /// <returns>写入是否成功</returns>
        public async Task<bool> WriteFloatAsync(string address, float value)
        {
            try
            {
                var result = await _plc.WriteAsync(address, value);
                if (result.IsSuccess)
                {
                    _mqttTopicLogger.WritePLCOperation("写入Float", address, value.ToString(), "成功");
                    return true;
                }
                else
                {
                    _mqttTopicLogger.WritePLCOperation("写入Float", address, value.ToString(), $"失败: {result.Message}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                _mqttTopicLogger.WriteSystemError($"写入 Float 数据时发生错误：{ex.Message}", ex);
                return false;
            }
        }

        /// <summary>
        /// 写入 Short 数据到 PLC
        /// </summary>
        /// <param name="address">PLC 地址</param>
        /// <param name="value">要写入的 Short 值</param>
        /// <returns>写入是否成功</returns>
        public async Task<bool> WriteShortAsync(string address, short value)
        {
            try
            {
                var result = await _plc.WriteAsync(address, value);
                if (result.IsSuccess)
                {
                    _mqttTopicLogger.WritePLCOperation("写入Short", address, value.ToString(), "成功");
                    return true;
                }
                else
                {
                    _mqttTopicLogger.WritePLCOperation("写入Short", address, value.ToString(), $"失败: {result.Message}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                _mqttTopicLogger.WriteSystemError($"写入 Short 数据时发生错误：{ex.Message}", ex);
                return false;
            }
        }

        /// <summary>
        /// 写入 Bool 数据到 PLC
        /// </summary>
        /// <param name="address">PLC 地址</param>
        /// <param name="value">要写入的 Bool 值</param>
        /// <returns>写入是否成功</returns>
        public async Task<bool> WriteBoolAsync(string address, bool value)
        {
            try
            {
                var result = await _plc.WriteAsync(address, value);
                if (result.IsSuccess)
                {
                    _mqttTopicLogger.WritePLCOperation("写入Bool", address, value.ToString(), "成功");
                    return true;
                }
                else
                {
                    _mqttTopicLogger.WritePLCOperation("写入Bool", address, value.ToString(), $"失败: {result.Message}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                _mqttTopicLogger.WriteSystemError($"写入 Bool 数据时发生错误：{ex.Message}", ex);
                return false;
            }
        }

        /// <summary>
        /// 写入 String 数据到 PLC
        /// </summary>
        /// <param name="address">PLC 地址</param>
        /// <param name="value">要写入的 String 值</param>
        /// <returns>写入是否成功</returns>
        public async Task<bool> WriteStringAsync(string address, string value)
        {
            try
            {
                var result = await _plc.WriteAsync(address, value);
                if (result.IsSuccess)
                {
                    _mqttTopicLogger.WritePLCOperation("写入String", address, value, "成功");
                    return true;
                }
                else
                {
                    _mqttTopicLogger.WritePLCOperation("写入String", address, value, $"失败: {result.Message}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                _mqttTopicLogger.WriteSystemError($"写入 String 数据时发生错误：{ex.Message}", ex);
                return false;
            }
        }

        private object[] ParseData(byte[] content, PLCDataType dataType)
        {
            switch (dataType)
            {
                case PLCDataType.Short:
                    return ParseShortData(content);
                case PLCDataType.Float:
                    return ParseFloatData(content);
                default:
                    throw new ArgumentException($"不支持的数据类型：{dataType}");
            }
        }

        private object[] ParseShortData(byte[] content)
        {
            int count = content.Length / 2;
            return Enumerable.Range(0, count)
                .Select(i => (object)ShortLib.GetShortFromByteArray(content, i * 2))
                .ToArray();
        }

        private object[] ParseFloatData(byte[] content)
        {
            int count = content.Length / 4;
            return Enumerable.Range(0, count)
                .Select(i => (object)FloatLib.GetFloatFromByteArray(content, i * 4))
                .ToArray();
        }
    }

    public static class ConvertHelper
    {
        /// <summary>
        /// 字节数组高低位转换
        /// </summary>
        /// <param name="Arrbyte"></param>
        /// <returns></returns>
        public static byte[] ByteReverse(this byte[] Arrbyte)
        {
            byte[] ArrByte = Arrbyte.Select((x, i) => new { x, i }).GroupBy(x => x.i / 2).SelectMany(x => new byte[] { x.Last().x, x.First().x }).ToArray();
            return ArrByte;
        }
    }
}
